fix(upgrade): refresh installer-written agent surfaces after a binary upgrade (#1238)#1239
Conversation
… upgrade codegraph upgrade swapped the binary but never revisited what earlier installs wrote into CLAUDE.md / AGENTS.md / GEMINI.md and the agent configs, so sections written by a pre-1.0 installer kept teaching agents a multi-tool surface (including tools that no longer exist) months of releases later. The install path already self-heals everything it owns, but nothing ever called it on upgrade. - codegraph install --refresh: non-interactive sweep that re-runs install() for already-configured targets only — never a first install; permissions and prompt-hook choices are preserved. - codegraph upgrade spawns it via the freshly-installed binary after a successful swap (the still-running old process would only rewrite its own stale template). Gated on PATH resolution and the CODEGRAPH_NO_INSTALL_REFRESH=1 kill-switch; never fatal to the upgrade. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR ensures that after codegraph upgrade swaps in a new binary, any agent-facing surfaces previously written by older installers (marker-fenced instruction blocks and MCP entries) are refreshed so they match the tool surface and templates of the newly-installed version.
Changes:
- Add a refresh-only sweep (
codegraph install --refresh) that re-runs per-targetinstall()only for already-configured targets, preserving permissions and prompt-hook choices. - Invoke that sweep automatically at the end of a successful
codegraph upgrade(non-fatal, PATH-gated, opt-out viaCODEGRAPH_NO_INSTALL_REFRESH=1). - Add unit tests covering upgrade orchestration and refresh sweep behavior/idempotency.
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/upgrade/index.ts | Spawns codegraph install --refresh after successful upgrades (with platform-specific Windows handling and kill-switch). |
| src/installer/index.ts | Introduces refreshTargets() and RefreshReport to refresh already-configured targets only. |
| src/bin/codegraph.ts | Adds codegraph install --refresh CLI flag and wires it to refreshTargets(). |
| CHANGELOG.md | Documents the new upgrade-time refresh behavior and manual install --refresh usage. |
| tests/upgrade.test.ts | Adds orchestration tests verifying refresh spawn timing, Windows invocation, gating, kill-switch, and non-fatal failure behavior. |
| tests/installer-targets.test.ts | Adds refresh sweep tests for stale block rewrite, “no first install”, permissions preservation, and idempotency. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
… resolved version after every upgrade (#1238, #1071) (#1245) Two fixes to make `codegraph upgrade` trustworthy in the terminal it ran in: 1. detectInstallMethod checked the bundle layout before the node_modules path check, but the npm thin-installer's per-platform package IS a complete bundle inside node_modules — so every npm install misdetected as a standalone bundle, and upgrade curled install.sh into ~/.codegraph: a second install that never wins the PATH race against npm's shim, leaving `codegraph -v` permanently on the old version. Path-based checks (_npx, node_modules) now win over layout sniffing, so npm installs upgrade through npm again, in place. 2. After a successful swap, runUpgrade now probes the PATH-resolved `codegraph --version` and reports the real outcome: a green confirmation that this terminal already serves the new version, a loud shadow warning naming the fix (`which -a codegraph`) on mismatch, or the old soft new-terminal hint only when the probe is inconclusive. Replaces the unconditional "open a new terminal if the version looks unchanged" hedge. Skipped for npm-local installs, whose binary PATH never serves. Companion to #1239: the misdetection also broke its post-upgrade `install --refresh` for npm users (the spawn resolved the stale shim). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…he version probe Conflict resolution after colbymchenry#1245 landed, plus the integration it called for: runUpgrade now runs the PATH version probe first and skips spawning `codegraph install --refresh` on a 'mismatch' — a shadowed stale binary would rewrite the agent surfaces with the very templates the refresh exists to heal. The skip logs a pointer to run the refresh manually once the PATH is fixed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Merged — thanks @xuing, this was a well-built fix: the refresh-only semantics, the new-binary spawn, and the test coverage all held up under validation (unit suites + live e2e on macOS, Linux/Docker, and Windows). Note on the final commit: rather than ask you to rebase, I resolved the post-#1245 conflict directly on your branch and wired the two PRs together — Both fixes ship in the next release. Your follow-up offer on the legacy codex 🤖 Generated with Claude Code |
Fixes #1238.
Problem
codegraph upgradeupdates the binary, but never revisits what earlier installs wrote into the agents. On a machine using CodeGraph since 0.9.x, every upgrade through 1.3.1 left the marker-fencedCLAUDE.md/AGENTS.mdsections exactly as the 0.9.x installer wrote them: a nine-tool decision table telling agents to reach forcodegraph_contextfirst — a tool 1.0.0 removed — and for six other tools that no longer appear on the default MCP surface. Agents follow the file, get "unknown tool", and conclude CodeGraph is broken. Full timeline in #1238.Every write in the install path is already an idempotent, self-healing upsert (the pre-#529 long-block heal, the pre-0.8 hook cleanup, the pre-#207 local-MCP migration) — but nothing ever invokes it on upgrade, so all that healing only reaches users who happen to re-run
codegraph installby hand.Approach
Extends the precedent already in the upgrade path:
runUpgradeself-heals the Claude prompt hook after a successful swap. This PR does the same for the rest of the installed surfaces, with one twist the prompt hook didn't need: the instruction templates are baked into the binary, so the heal must be executed by the new binary — the still-running old process would only rewrite its own stale copy, the exact staleness being healed.codegraph install --refresh— a non-interactive sweep (same shape asuninstallTargets, exposed and unit-tested the same way) that re-runsinstall()for every target that is already configured. Never a first install: unconfigured agents are skipped, permissions aren't written (autoAllow: false), and the prompt hook is left as the user chose it (promptHook: undefined). Sweeps global + local unless--locationnarrows it.codegraph upgradespawnscodegraph install --refreshafter a successful binary swap — PATH resolves to the fresh install at that point. Gated oncodegraphbeing resolvable (an npm-local install isn't), opt-out viaCODEGRAPH_NO_INSTALL_REFRESH=1, and never fatal to the upgrade.Nothing changes on a machine that's already current: every underlying write is the targets' own byte-compare upsert, so the sweep reports
unchangedacross the board and prints one quiet line.What it looks like
On an already-current machine:
Tests
runUpgradeorchestration tests: the refresh is spawned last (after the swap, so the new binary writes); Windows runs the.cmdlauncher throughcmd.exe; skipped whencodegraphisn't on PATH; skipped by the kill-switch; a failing refresh warns without failing the upgrade; no refresh after a failed upgrade.refreshTargetssweep tests: rewrites a planted stale block and reportsrefreshed; never performs a first install; preserves a hand-trimmed permissions list; second sweep is all-unchanged.$HOME,install -t claude -l global -y→ plant the 0.9.x section →install --refreshrewrites it to the current template → second--refreshreports already-current.Not in this PR
Old codex installers also wrote per-tool
approval_modeblocks ([mcp_servers.codegraph.tools.*]) that can reference tools which no longer exist;install()doesn't own those keys today, so the sweep doesn't clean them. That would be a target-level cleanup in the codex target, same pattern as the existing legacy-hook cleanup — happy to follow up if wanted.🤖 Proudly generated using Fable 5, and reviewed with GPT5.6 sol.